#include "util.h"
#include "macro.h"
#include "timer.h"

/**
 * @brief 定时器模块的实现
 * @details
 * 1.获取需要执行的定时器的回调函数列表
 * 思路:以当前时间为超时时间的定时器加入到时间堆里面,找到等于现在超时的定时器的最后一个位置,返回这区间的回调函数
 * 2.到下一个定时器执行的时间间隔ms
 * 获取当前的系统时间,和最小堆对顶的超时时间进行对比
 */

bool Timer::Comparator::operator()(const Timer::ptr &lptr, const Timer::ptr &rptr) const
{
    if (lptr == nullptr && rptr == nullptr)
        return false;
    if (lptr == nullptr)
        return true;
    if (rptr == nullptr)
        return false;
    if (lptr->m_next < rptr->m_next)
        return true;
    if (rptr->m_next < lptr->m_next)
        return false;
    return lptr.get() < rptr.get();
}

Timer::Timer(uint64_t ms, std::function<void()> cb, bool recurring, TimerManager *manager)
    : m_recurring(recurring), m_ms(ms), m_cb(cb), m_manager(manager)
{
    // 下一次的执行时间等于当前的时间+执行周期
    m_next = GetElapsedMS() + m_ms;
}

// 绝对时间构造定时器
Timer::Timer(uint64_t next)
    : m_next(next)
{
}

bool Timer::cancel()
{
    TimerManager::RWMutexType::WriteLock lock(m_manager->m_mutex);
    if (m_cb)
    {
        m_cb = nullptr;
        auto it = m_manager->m_timers.find(shared_from_this());
        m_manager->m_timers.erase(it);
        return true;
    }
    return false;
}

bool Timer::refresh()
{
    TimerManager::RWMutexType::WriteLock lock(m_manager->m_mutex);
    if (m_cb == nullptr)
        return false;
    auto it = m_manager->m_timers.find(shared_from_this());
    if (it == m_manager->m_timers.end())
    {
        return false;
    }
    m_manager->m_timers.erase(it);
    m_next = GetElapsedMS() + m_ms;
    m_manager->m_timers.insert(shared_from_this());
    return true;
}

bool Timer::reset(uint64_t ms, bool from_now)
{
    if (m_ms == ms && from_now == false)
        return true;

    TimerManager::RWMutexType::WriteLock lock(m_manager->m_mutex);
    if (m_cb == nullptr)
        return false;
    auto it = m_manager->m_timers.find(shared_from_this());
    if (it == m_manager->m_timers.end())
    {
        return false;
    }
    m_manager->m_timers.erase(it);
    uint64_t start = 0;
    if (from_now)
    {
        start = GetElapsedMS();
    }
    else
    {
        start = m_next - m_ms;
    }
    m_ms = ms;
    m_next = start + m_ms;
    m_manager->addTimer(shared_from_this(), lock);
    return true;
}

TimerManager::TimerManager()
{
    m_previousTime = GetElapsedMS();
}

TimerManager::~TimerManager() {}

Timer::ptr TimerManager::addTimer(uint64_t ms, std::function<void()> cb, bool recurring)
{
    Timer::ptr timer(new Timer(ms, cb, recurring, this));
    RWMutexType::WriteLock lock(m_mutex);
    addTimer(timer, lock);
    return timer;
}

static void OnTimer(std::weak_ptr<void> weak_cond, std::function<void()> cb)
{
    std::shared_ptr<void> tmp = weak_cond.lock();
    if (tmp)
    {
        cb();
    }
}

Timer::ptr TimerManager::addConditionTimer(uint64_t ms, std::function<void()> cb, std::weak_ptr<void> weak_cond, bool recurring)
{
    return addTimer(ms, std::bind(&OnTimer, weak_cond, cb), recurring);
}

// 到下一个定时器执行的时间间隔ms
uint64_t TimerManager::getNextTimer()
{
    RWMutexType::ReadLock lock(m_mutex);
    m_tickled = false;
    if (m_timers.empty())
    {
        return ~0ull;
    }

    const Timer::ptr &next = *m_timers.begin();
    uint64_t now_ms = GetElapsedMS();
    if (now_ms >= next->m_next)
    {
        return 0;
    }
    else
    {
        return next->m_next - now_ms;
    }
}

// 获取需要执行的定时器的回调函数列表
void TimerManager::listExpireCb(std::vector<std::function<void()>> &cbs)
{
    uint64_t now_ms = GetElapsedMS();
    std::vector<Timer::ptr> expired;
    // 定时器集合为空直接返回
    {
        RWMutexType::ReadLock lock(m_mutex);
        if (m_timers.empty())
            return;
    }

    RWMutexType::WriteLock lock(m_mutex);
    if (m_timers.empty())
        return;

    // 检测服务器时间是否被调后了
    bool rollover = false;
    if (SYLAR_UNLIKELY(delectClockRollover(now_ms)))
    {
        // 使用clock_gettime(CLOCK_MONOTONIC_RAW)应该不可能出现时间回退的问题
        rollover = true;
    }

    if (!rollover && ((*m_timers.begin())->m_next > now_ms))
        return;

    Timer::ptr now_timer(new Timer(now_ms));
    // 找到等于现在超时的定时器的最后一个位置
    auto it = rollover ? m_timers.end() : m_timers.lower_bound(now_timer);
    while (it != m_timers.end() && (*it)->m_next == now_ms)
        ++it;

    expired.insert(expired.begin(), m_timers.begin(), it);
    m_timers.erase(m_timers.begin(), it);
    cbs.reserve(expired.size());

    for (auto &timer : expired)
    {
        cbs.push_back(timer->m_cb);
        if (timer->m_recurring)
        {
            timer->m_next = now_ms + timer->m_ms;
            m_timers.insert(timer);
        }
        else
        {
            timer->m_cb = nullptr;
        }
    }
}

void TimerManager::addTimer(Timer::ptr val, RWMutexType::WriteLock &lock)
{
    auto it = m_timers.insert(val).first;
    bool at_front = (it == m_timers.begin()) && !m_tickled;
    if (at_front)
    {
        m_tickled = true;
    }
    lock.unlock();
    if (at_front)
    {
        // 当有新的定时器插入到定时器的首部,执行该函数
        onTimerInsertAtFront();
    }
}

// 检测服务器时间是否被调后了
bool TimerManager::delectClockRollover(uint64_t now_ms)
{
    bool rollover = false;
    if (now_ms <= m_previousTime && now_ms < (m_previousTime - 60 * 60 * 1000))
    {
        rollover = true;
    }

    m_previousTime = now_ms;
    return rollover;
}

bool TimerManager::hasTimer()
{
    RWMutexType::ReadLock lock(m_mutex);
    return !m_timers.empty();
}
